return ret;
}
+/**
+ * ostree_repo_resolve_partial_checksum:
+ * @self: Repo
+ * @refspec: A refspec
+ * @full_checksum (out) (transfer full): A full checksum corresponding to the truncated ref given
+ * @error: Error
+ *
+ * Look up the existing refspec checksums. If the given ref is a unique truncated beginning
+ * of a valid checksum it will return that checksum in the parameter @full_checksum
+ */
+static gboolean
+ostree_repo_resolve_partial_checksum (OstreeRepo *self,
+ const char *refspec,
+ char **full_checksum,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ s_unref_hashtable GHashTable *ref_list = NULL;
+ gs_free char *ret_rev = NULL;
+ guint length;
+ const char *checksum = NULL;
+ OstreeObjectType objtype;
+ GHashTableIter hashiter;
+ gpointer key, value;
+ GVariant *first_commit;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* this looks through all objects and adds them to the ref_list if:
+ a) they are a commit object AND
+ b) the obj checksum starts with the partual checksum defined by "refspec" */
+ if (!ostree_repo_list_commit_objects_starting_with (self, refspec, &ref_list, NULL, error))
+ goto out;
+
+ length = g_hash_table_size (ref_list);
+
+ g_hash_table_iter_init (&hashiter, ref_list);
+ if (g_hash_table_iter_next (&hashiter, &key, &value))
+ first_commit = (GVariant*) key;
+ else
+ first_commit = NULL;
+
+ if (first_commit)
+ ostree_object_name_deserialize (first_commit, &checksum, &objtype);
+
+ /* length more than one - multiple commits match partial refspec: is not unique */
+ if (length > 1)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Refspec %s not unique", refspec);
+ goto out;
+ }
+
+ /* length is 1 - a single matching commit gives us our revision */
+ else if (length == 1)
+ {
+ ret_rev = g_strdup (checksum);
+ }
+
+ /* Note: if length is 0, then code will return TRUE
+ because there is no error, but it will return full_checksum = NULL
+ to signal to continue parsing */
+
+ ret = TRUE;
+ ot_transfer_out_value (full_checksum, &ret_rev);
+ out:
+ return ret;
+}
+
/**
* ostree_repo_resolve_rev:
* @self: Repo
{
ret_rev = g_strdup (refspec);
}
- else
+
+ else if (!ostree_repo_resolve_partial_checksum (self, refspec, &ret_rev, error))
+ goto out;
+
+ if (!ret_rev)
{
+ if (error != NULL && *error != NULL)
+ goto out;
+
if (g_str_has_suffix (refspec, "^"))
{
gs_free char *parent_refspec = NULL;
GHashTable *inout_objects,
const char *prefix,
int dfd,
+ const char *commit_starting_with,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
DIR *d = NULL;
struct dirent *dent;
+ GVariant *key, *value;
d = fdopendir (dfd);
if (!d)
else
continue;
- if ((dot - name) == 62)
+ if ((dot - name) != 62)
+ continue;
+
+ memcpy (buf, prefix, 2);
+ memcpy (buf + 2, name, 62);
+ buf[sizeof(buf)-1] = '\0';
+
+ /* if we passed in a "starting with" argument, then
+ we only want to return .commit objects with a checksum
+ that matches the commit_starting_with argument */
+ if (commit_starting_with)
{
- GVariant *key, *value;
-
- memcpy (buf, prefix, 2);
- memcpy (buf + 2, name, 62);
- buf[sizeof(buf)-1] = '\0';
-
- key = ostree_object_name_serialize (buf, objtype);
- value = g_variant_new ("(b@as)",
- TRUE, g_variant_new_strv (NULL, 0));
- /* transfer ownership */
- g_hash_table_replace (inout_objects, key,
- g_variant_ref_sink (value));
+ /* object is not a commit, do not add to array */
+ if (objtype != OSTREE_OBJECT_TYPE_COMMIT)
+ continue;
+
+ /* commit checksum does not match "starting with", do not add to array */
+ if (!g_str_has_prefix (buf, commit_starting_with))
+ continue;
}
+
+ key = ostree_object_name_serialize (buf, objtype);
+ value = g_variant_new ("(b@as)",
+ TRUE, g_variant_new_strv (NULL, 0));
+ /* transfer ownership */
+ g_hash_table_replace (inout_objects, key,
+ g_variant_ref_sink (value));
}
ret = TRUE;
static gboolean
list_loose_objects (OstreeRepo *self,
GHashTable *inout_objects,
+ const char *commit_starting_with,
GCancellable *cancellable,
GError **error)
{
}
/* Takes ownership of dfd */
if (!list_loose_objects_at (self, inout_objects, buf, dfd,
- cancellable, error))
+ commit_starting_with,
+ cancellable, error))
goto out;
}
if (flags & OSTREE_REPO_LIST_OBJECTS_LOOSE)
{
- if (!list_loose_objects (self, ret_objects, cancellable, error))
+ if (!list_loose_objects (self, ret_objects, NULL, cancellable, error))
goto out;
if (self->parent_repo)
{
- if (!list_loose_objects (self->parent_repo, ret_objects, cancellable, error))
+ if (!list_loose_objects (self->parent_repo, ret_objects, NULL, cancellable, error))
goto out;
}
}
return ret;
}
+/**
+ * ostree_repo_list_commit_objects_starting_with:
+ * @self: Repo
+ * @start: List commits starting with this checksum
+ * @out_commits: Array of GVariants
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * This function synchronously enumerates all commit objects starting
+ * with @start, returning data in @out_commits.
+ *
+ * Returns: %TRUE on success, %FALSE on error, and @error will be set
+ */
+gboolean
+ostree_repo_list_commit_objects_starting_with (OstreeRepo *self,
+ const char *start,
+ GHashTable **out_commits,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_hashtable GHashTable *ret_commits = NULL;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (self->inited, FALSE);
+
+ ret_commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
+ (GDestroyNotify) g_variant_unref,
+ (GDestroyNotify) g_variant_unref);
+
+ if (!list_loose_objects (self, ret_commits, start, cancellable, error))
+ goto out;
+
+
+ if (self->parent_repo)
+ {
+ if (!list_loose_objects (self->parent_repo, ret_commits, start,
+ cancellable, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ ot_transfer_out_value (out_commits, &ret_commits);
+ out:
+ return ret;
+}
+
/**
* ostree_repo_read_commit:
* @self: Repo